home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / KILL.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  16KB  |  762 lines

  1. #include "config.h"
  2. #include "term.h"
  3. #include "regexp.h"
  4.  
  5. /*
  6.  * kill file handling
  7.  */
  8.  
  9. export int killed_articles;
  10.  
  11. char KILL_FILE[] =     "kill";
  12. char COMPILED_KILL[] =    "KILL.COMP";
  13.  
  14. extern char *quick_match();
  15.  
  16. #define COMP_KILL_MAGIC    0x4b694c6d    /* KiLm */
  17.  
  18. /*
  19.  * kill flags
  20.  */
  21.  
  22. #define COMP_KILL_ENTRY    0x80
  23.  
  24. #define    AUTO_KILL    0x01
  25. #define AUTO_SELECT    0x00    /* pseudo flag */
  26. #define ON_SUBJECT    0x02
  27. #define    ON_SENDER    0x00    /* pseudo flag */
  28.  
  29. #define    KILL_MUST_MATCH    0x10
  30. #define KILL_ON_REGEXP    0x20
  31.  
  32. /*
  33.  * external flag representation
  34.  */
  35.  
  36. #define    EXT_AUTO_KILL        '!'
  37. #define EXT_AUTO_SELECT        '+'
  38. #define EXT_ON_SUBJECT        's'
  39. #define    EXT_ON_SENDER        'n'
  40. #define    EXT_KILL_MUST_MATCH    '='
  41. #define EXT_KILL_ON_REGEXP    '/'
  42.  
  43. /*
  44.  * period = nnn DAYS
  45.  */
  46.  
  47. #define    DAYS    * 24 * 60 * 60
  48.  
  49.  
  50. /*
  51.  * kill_article
  52.  *
  53.  *    return 1 to kill article, 0 to include it
  54.  */
  55.  
  56. typedef struct kill_list_entry {
  57.     int kill_flag;
  58.     char *kill_pattern;
  59.     regexp *kill_regexp;
  60.     struct kill_list_entry *next_kill;
  61. } kill_list_entry;
  62.  
  63. static kill_list_entry *kill_tab;
  64. static char *kill_patterns;
  65.  
  66. static kill_list_entry dummy_kill = {
  67.     0, (char *)NULL, (regexp *)NULL, (kill_list_entry *)NULL 
  68. };
  69. static kill_list_entry *global_kill_list = &dummy_kill;
  70. static kill_list_entry *end_kill_list = &dummy_kill;
  71. static kill_list_entry latest_kl_entry;
  72.  
  73. kill_article(ah)
  74. article_header *ah;
  75. {
  76.     register kill_list_entry *kl;
  77.     char *string;
  78.     
  79.     end_kill_list->next_kill = (kill_list_entry *)(current_group->kill_list);
  80.     
  81.     kl = global_kill_list;
  82.     while (kl = kl->next_kill) {
  83.     if (kl->kill_flag & ON_SUBJECT)
  84.         string = ah->subject;
  85.     else
  86.         string = ah->sender;
  87.     
  88.     if (kl->kill_flag & KILL_MUST_MATCH) {
  89.         if (strcmp(kl->kill_pattern, string))
  90.         continue;
  91.     } else
  92.     if (kl->kill_flag & KILL_ON_REGEXP) {
  93.         if (regexec(kl->kill_regexp, string) == 0)
  94.         continue;
  95.     } else
  96.         if (quick_match(string, kl->kill_pattern) == NULL)
  97.         continue;
  98.     
  99.     if (kl->kill_flag & AUTO_KILL) {
  100.         killed_articles++;
  101.         return 1;
  102.     }
  103.     
  104.     ah->flag |= A_SELECT | A_AUTO;
  105.     break;
  106.     }
  107.     
  108.     return 0;
  109. }
  110.  
  111.  
  112. auto_select_article(ah, do_select)
  113. article_header *ah;
  114. int do_select;
  115. {
  116.     register kill_list_entry *kl;
  117.     kill_list_entry kl_head;
  118.     char *string;
  119.  
  120.     if (do_select == 2) {
  121.     kl = &kl_head;
  122.     kl->next_kill = &latest_kl_entry;
  123.     } else {
  124.     end_kill_list->next_kill = ah->a_group ?
  125.         (kill_list_entry *)(ah->a_group->kill_list) :
  126.         (kill_list_entry *)(current_group->kill_list);
  127.     kl = global_kill_list;
  128.     }
  129.     
  130.     while (kl = kl->next_kill) {
  131.     if (do_select) {
  132.         if (kl->kill_flag & AUTO_KILL) continue;
  133.     } else {
  134.         if ((kl->kill_flag & AUTO_KILL) == 0) continue;
  135.     }
  136.      check_one:    
  137.     if (kl->kill_flag & ON_SUBJECT)
  138.         string = ah->subject;
  139.     else
  140.         string = ah->sender;
  141.     
  142.     if (kl->kill_flag & KILL_MUST_MATCH) {
  143.         if (strcmp(kl->kill_pattern, string))
  144.         continue;
  145.     } else
  146.     if (kl->kill_flag & KILL_ON_REGEXP) {
  147.         if (regexec(kl->kill_regexp, string) == 0)
  148.         continue;
  149.     } else
  150.         if (quick_match(string, kl->kill_pattern) == NULL)
  151.         continue;
  152.     killed_articles++;
  153.     return 1;
  154.     }
  155.     
  156.     return 0;
  157. }
  158.  
  159.  
  160.  
  161.  
  162.  
  163. enter_kill_file(gh, pattern, flag, days)
  164. group_header *gh;
  165. char *pattern;
  166. int flag;
  167. int days;
  168. {
  169.     time_t now;
  170.     FILE *killf;
  171.     register kill_list_entry *kl;
  172.     regexp *re;
  173.     char *str;
  174.     
  175.     str = copy_str(pattern);
  176.     
  177.     if (flag & KILL_ON_REGEXP) {
  178.     re = regcomp(pattern);
  179.     if (re == NULL) return;
  180.     } else {
  181.     re = NULL;
  182.     if ((flag & KILL_MUST_MATCH) == 0)
  183.         init_quick_match(str);
  184.     }
  185.     
  186.     killf = open_file(relative(nn_directory, "kill"), OPEN_APPEND);
  187.     if (killf == NULL) {
  188.     msg("cannot create kill file");
  189.     return;
  190.     }
  191.     
  192.     if (days >= 0) {
  193.     time(&now);
  194.     if (days == 0) days = 30;
  195.     fprintf(killf, "%lu:", (long)(now + days DAYS));
  196.     }
  197.  
  198.     if (gh) fputs(gh->group_name, killf);
  199.     fputc(':', killf);
  200.  
  201.     fputc(flag & AUTO_KILL ? EXT_AUTO_KILL : EXT_AUTO_SELECT, killf);
  202.     fputc(flag & ON_SUBJECT ? EXT_ON_SUBJECT : EXT_ON_SENDER, killf);
  203.     if (flag & KILL_MUST_MATCH) fputc(EXT_KILL_MUST_MATCH, killf);
  204.     if (flag & KILL_ON_REGEXP) fputc(EXT_KILL_ON_REGEXP, killf);
  205.     fputc(':', killf);
  206.  
  207.     fputs(pattern, killf);
  208.     fputc(NL, killf);
  209.     
  210.     fclose(killf);
  211.     rm_kill_file();
  212.     
  213.     kl = (kill_list_entry *)calloc(1, sizeof(kill_list_entry));
  214.     mem_check((char *)kl, 1, "kill list entry");
  215.     
  216.     latest_kl_entry.kill_pattern = kl->kill_pattern = str;
  217.     latest_kl_entry.kill_regexp = kl->kill_regexp = re;
  218.     latest_kl_entry.kill_flag = kl->kill_flag = flag;
  219.     latest_kl_entry.next_kill = NULL;
  220.     
  221.     if (gh) {
  222.     kl->next_kill = (kill_list_entry *)(gh->kill_list);
  223.     gh->kill_list = (char *)kl;
  224.     } else {
  225.     kl->next_kill = NULL;
  226.     end_kill_list->next_kill = kl;
  227.     end_kill_list = kl;
  228.     }
  229. }
  230.  
  231.  
  232. typedef struct {
  233.     group_number    ck_group;
  234.     char        ck_flag;
  235.     long        ck_pattern_index;
  236. } comp_kill_entry;
  237.  
  238. typedef struct {
  239.     long        ckh_magic;
  240.     off_t        ckh_pattern_offset;
  241.     long        ckh_pattern_size;
  242.     long        ckh_entries;
  243. } comp_kill_header;
  244.  
  245.  
  246. kill_menu(ah)
  247. article_header *ah;
  248. {
  249.     int flag, days;
  250.     char *mode1, *mode2;
  251.     char *pattern, *dflt, *days_str, buffer[512];
  252.     extern article_header *get_menu_article();
  253.     group_header *gh;
  254.     
  255.     prompt("\1AUTO\1 (K)ill or (S)elect (CR => Kill subject 1 month) ");
  256.     switch (get_c()) {
  257.      case CR:
  258.      case NL:
  259.     if (ah == NULL) {
  260.         ah = get_menu_article();
  261.         if (ah == NULL) return -1;
  262.     }
  263.     
  264.     strcpy(buffer, ah->subject);
  265.     enter_kill_file(current_group, buffer, 
  266.             AUTO_KILL | ON_SUBJECT | KILL_MUST_MATCH, 30);
  267.     msg("DONE");
  268.     return 1;
  269.     
  270.      case 'k':
  271.      case 'K':
  272.      case '!':
  273.     flag = AUTO_KILL;
  274.     mode1 = "KILL";
  275.     break;
  276.      case 's':
  277.      case 'S':
  278.      case '+':
  279.     flag = AUTO_SELECT;
  280.     mode1 = "SELECT";
  281.     break;
  282.      default:
  283.     return -1;
  284.     }
  285.     
  286.     prompt("\1AUTO %s\1 on (S)ubject or (N)ame ?", mode1);
  287.     
  288.     dflt = NULL;
  289.     switch (get_c()) {
  290.      case 'n':
  291.      case 'N':
  292.     flag |= ON_SENDER;
  293.     if (ah) dflt = ah->sender;
  294.     mode2 = "Name";
  295.     break;
  296.      case 's':
  297.      case 'S':
  298.      case SP:
  299.      case CR:
  300.      case NL:
  301.     flag |= ON_SUBJECT;
  302.     if (ah) dflt = ah->subject;
  303.     mode2 = "Subject";
  304.     break;
  305.      default:
  306.     return -1;
  307.     }
  308.  
  309.     prompt("\1%s %s:\1", mode1, mode2);
  310.     
  311.     pattern = get_s(dflt, NONE, "%=/", NO_COMPLETION);
  312.     if (pattern == NULL) return -1;
  313.     if (*pattern == NUL || *pattern == '%' || *pattern == '=') {
  314.     if (dflt && *dflt)
  315.         pattern = dflt;
  316.     else {
  317.         if ((ah = get_menu_article()) == NULL) return -1;
  318.         pattern = (flag & ON_SUBJECT) ? ah->subject : ah->sender;
  319.     }
  320.     flag |= KILL_MUST_MATCH;
  321.     } else
  322.     if (*pattern == '/') {
  323.         prompt("\1%s %s\1 (regexp): ", mode1, mode2);
  324.     
  325.         pattern = get_s(NONE, NONE, NONE, NO_COMPLETION);
  326.         if (pattern == NULL || *pattern == NUL) return -1;
  327.         flag |= KILL_ON_REGEXP;
  328.     }
  329.     
  330.     strcpy(buffer, pattern);
  331.     pattern = buffer;
  332.     
  333.     prompt("\1%s\1 in (G)roup '%s' or in (A)ll groups",
  334.        mode1, current_group->group_name);
  335.     
  336.     switch (get_c()) {
  337.       case 'g':
  338.       case 'G':
  339.       case SP:
  340.       case CR:
  341.       case NL:
  342.      gh = current_group;
  343.      break;
  344.       case 'A':
  345.       case 'a':
  346.      gh = NULL;
  347.      break;
  348.       default:
  349.      return -1;
  350.      }
  351.  
  352.     prompt("\1Lifetime of entry in days\1 (P)ermanent ");
  353.     days_str = get_s(" 30 days", NONE, "pP", NO_COMPLETION);
  354.     if (days_str == NULL) return -1;
  355.  
  356.     if (*days_str == NUL) {
  357.         days_str = "30 days";
  358.     days = 30;
  359.     } else if (*days_str == 'p' || *days_str == 'P') {
  360.     days_str = "perm";
  361.     days = -1;
  362.     } else if (isdigit(*days_str)) {
  363.     days = atoi(days_str);
  364.     sprintf(days_str, "%d days", days);
  365.     } else {
  366.     ding();
  367.     return -1;
  368.     }
  369.  
  370.     prompt("\1CONFIRM\1 %s %s %s%s: %-.35s%s ",
  371.        mode1, mode2, days_str, 
  372.        (flag & KILL_MUST_MATCH) ? " exact" : 
  373.        (flag & KILL_ON_REGEXP) ? " regexp" : "",
  374.        pattern, strlen(pattern) > 35 ? "..." : "");
  375.     if (yes(0) <= 0) return -1;
  376.     
  377.     enter_kill_file(gh, pattern, flag, days);
  378.  
  379.     return (flag & AUTO_KILL) ? 1 : 0;
  380. }
  381.  
  382.  
  383.     
  384.  
  385. init_kill()
  386. {
  387.     FILE *killf;
  388.     comp_kill_header header;
  389.     comp_kill_entry  entry;
  390.     register group_header *gh;
  391.     register kill_list_entry *kl;
  392.     time_t kill_age, comp_age;
  393.     register long n;
  394.     int first_try = 1;
  395.     import char *delayed_msg;
  396.     
  397.     Loop_Groups_Header(gh)
  398.     gh->kill_list = NULL;
  399.  
  400.     kill_age = file_exist(relative(nn_directory, KILL_FILE), "frw");
  401.     if (kill_age == 0) return 0;
  402.     
  403.     comp_age = file_exist(relative(nn_directory, COMPILED_KILL), "fr");
  404.  again:
  405.     if (comp_age < kill_age && !compile_kill_file()) return 0;
  406.  
  407.     kill_tab = NULL;
  408.     kill_patterns = NULL;
  409.     
  410.     killf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_READ);
  411.     if (killf == NULL) return 0;
  412.  
  413.     if (fread((char *)&header, sizeof(header), 1, killf) != 1) goto err;
  414.     if (header.ckh_magic != COMP_KILL_MAGIC) goto err;
  415.  
  416.     kill_patterns = malloc((unsigned)header.ckh_pattern_size);
  417.     mem_check(kill_patterns, (int)header.ckh_pattern_size, "kill bytes");
  418.     
  419.     kill_tab = (kill_list_entry *)
  420.     calloc((unsigned)header.ckh_entries, sizeof(kill_list_entry));
  421.     mem_check((char *)kill_tab, (int)header.ckh_entries, "kill entries");
  422.  
  423.     fseek(killf, (off_t)(header.ckh_entries * sizeof(entry)), 1);
  424.     if (fread(kill_patterns, sizeof(char), (int)header.ckh_pattern_size, killf)
  425.     !=  header.ckh_pattern_size) goto err;
  426.  
  427.     fseek(killf, (off_t)sizeof(header), 0);
  428.     for (n = header.ckh_entries, kl = kill_tab; --n >= 0; kl++) {
  429.     if (fread((char *)&entry, sizeof(entry), 1, killf) != 1) goto err;
  430.     if (header.ckh_pattern_size <= entry.ck_pattern_index ||
  431.         entry.ck_pattern_index < 0) goto err;
  432.     
  433.     kl->kill_pattern = kill_patterns + entry.ck_pattern_index;
  434.     kl->kill_flag = entry.ck_flag;
  435.  
  436.     if (kl->kill_flag & KILL_ON_REGEXP)
  437.         kl->kill_regexp = regcomp(kl->kill_pattern);
  438.     else
  439.         kl->kill_regexp = NULL;
  440.     
  441.     if (entry.ck_group >= 0) {
  442.         gh = active_groups + entry.ck_group;
  443.         kl->next_kill = (kill_list_entry *)(gh->kill_list);
  444.         gh->kill_list = (char *)kl;
  445.     } else {
  446.         kl->next_kill = NULL;
  447.         end_kill_list->next_kill = kl;
  448.         end_kill_list = kl;
  449.     }
  450.     }
  451.           
  452.     fclose(killf);
  453.     
  454.     return 1;
  455.     
  456.  err:
  457.     if (kill_patterns != NULL) free(kill_patterns);
  458.     if (kill_tab != NULL) free(kill_tab);
  459.     
  460.     fclose(killf);
  461.     rm_kill_file();
  462.     if (first_try) {
  463.     first_try = 0;
  464.     comp_age = 0;
  465.     goto again;
  466.     }
  467.     
  468.     delayed_msg = "Error in compiled kill file (ignored)";
  469.  
  470.     Loop_Groups_Header(gh)
  471.     gh->kill_list = NULL;
  472.     
  473.     end_kill_list = global_kill_list = &dummy_kill;
  474.  
  475.     return 0;
  476. }
  477.  
  478.  
  479. static compile_kill_file()
  480. {
  481.     FILE *killf, *compf, *patternf, *dropf;
  482.     comp_kill_header header;
  483.     comp_kill_entry  entry;
  484.     time_t now, age;
  485.     off_t cur_line_start;
  486.     char line[512];
  487.     register char *cp, *np;
  488.     register int c;
  489.     group_header *gh;
  490.     int flag, any_errors;
  491.     extern char *temp_file;
  492.     
  493.     any_errors = 0;
  494.     header.ckh_entries = 0;
  495.     
  496.     killf = open_file(relative(nn_directory, KILL_FILE),
  497.               OPEN_READ | DONT_CREATE);
  498.     if (killf == NULL) return 0;
  499.  
  500.     compf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_CREATE);
  501.     if (compf == NULL) goto err1;
  502.  
  503.     new_temp_file();
  504.     if ((patternf = open_file(temp_file, OPEN_CREATE)) == NULL)
  505.     goto err2;
  506.  
  507.     dropf = NULL;
  508.  
  509.     printf("\nCompiling kill file\n");
  510.  
  511.     fseek(compf, (off_t)sizeof(header), 0);
  512.     
  513.     time(&now);
  514.     
  515.  next_entry:
  516.  
  517.     for (;;) {
  518.     cur_line_start = ftell(killf);
  519.     
  520.     if (fgets(line, 512, killf) == NULL) break;
  521.     
  522.     cp = line;
  523.     while (*cp && isascii(*cp) && isspace(*cp)) cp++;
  524.     if (*cp == NUL || *cp == '#' || !isascii(*cp)) continue;
  525.     
  526.     if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
  527.  
  528.     /* optional "age:" */
  529.  
  530.     if (np != cp && isdigit(*cp)) {
  531.         *np++ = NUL;
  532.         age = (time_t)atol(cp);
  533.         if (age < now) goto drop_entry;
  534.         cp = np;
  535.         if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
  536.     }
  537.  
  538.     /* "group-name:"  or ":" for all groups */
  539.  
  540.     if (np == cp) {
  541.         entry.ck_group = -1;
  542.         np++;
  543.     } else {
  544.         *np++ = NUL;
  545.         if ((gh = lookup(cp)) == NULL) {
  546.         printf("Unknown group in kill file: %s\n", cp);
  547.         any_errors++;
  548.         goto drop_entry;
  549.         }
  550.         entry.ck_group = gh->group_num;
  551.     }
  552.  
  553.     /* flags */
  554.  
  555.     cp = np;
  556.     flag = COMP_KILL_ENTRY;
  557.     
  558.     for (;;) {
  559.         switch (*cp++) {
  560.          case EXT_AUTO_KILL:
  561.         flag |= AUTO_KILL;
  562.         continue;
  563.          case EXT_AUTO_SELECT:
  564.         flag |= AUTO_SELECT;
  565.         continue;
  566.          case EXT_ON_SUBJECT:
  567.         flag |= ON_SUBJECT;
  568.         continue;
  569.          case EXT_ON_SENDER:
  570.         flag |= ON_SENDER;
  571.         continue;
  572.          case EXT_KILL_MUST_MATCH:
  573.         flag |= KILL_MUST_MATCH;
  574.         continue;
  575.          case EXT_KILL_ON_REGEXP:
  576.         flag |= KILL_ON_REGEXP;
  577.         continue;
  578.          case ':':
  579.         break;
  580.          case NL:
  581.         goto bad_entry;
  582.          default:
  583.         printf("Ignored flag '%c' in kill file\n", cp[-1]);
  584.         any_errors++;
  585.         continue;
  586.         }        
  587.         break;
  588.     }
  589.  
  590.     entry.ck_flag = flag;
  591.     
  592.     if ((np = strchr(cp, NL)) == NULL) goto bad_entry;
  593.     
  594.     *np++ = NUL;
  595.     if ((flag & (KILL_MUST_MATCH | KILL_ON_REGEXP)) == 0)
  596.         init_quick_match(cp);
  597.     
  598.     entry.ck_pattern_index = ftell(patternf);
  599.     
  600.     if (fwrite(&entry, sizeof(entry), 1, compf) != 1)
  601.         goto err3;
  602.  
  603.     if (fwrite(cp, sizeof(char), np - cp, patternf) != (np - cp)) 
  604.         goto err3;
  605.     
  606.     header.ckh_entries++;
  607.     }
  608.     
  609.     header.ckh_pattern_size = ftell(patternf);
  610.     
  611.     fclose(patternf);
  612.     patternf = open_file(temp_file, OPEN_READ | OPEN_UNLINK);
  613.     if (patternf == NULL) goto err2;
  614.     
  615.     header.ckh_pattern_offset = ftell(compf);
  616.     
  617.     while ((c = getc(patternf)) != EOF)
  618.     putc(c, compf);
  619.  
  620.     fclose(patternf);
  621.  
  622.     rewind(compf);
  623.  
  624.     header.ckh_magic = COMP_KILL_MAGIC;
  625.  
  626.     if (fwrite((char *)&header, sizeof(header), 1, compf) != 1)
  627.     goto err2;
  628.     
  629.     fclose(compf);
  630.     fclose(killf);
  631.     if (dropf != NULL) fclose(dropf);
  632.  
  633.     if (any_errors) {
  634.     putchar(NL);
  635.     any_key(0);
  636.     }
  637.     
  638.     return 1;
  639.     
  640.  bad_entry:
  641.     printf("Incomplete kill file entry:\n%s", line);
  642.     fl;
  643.     any_errors++;
  644.     
  645.  drop_entry:
  646.     if (dropf == NULL) {
  647.     dropf = open_file(relative(nn_directory, KILL_FILE),
  648.               OPEN_UPDATE | DONT_CREATE);
  649.     if (dropf == NULL) goto next_entry;
  650.     }
  651.     fseek(dropf, cur_line_start, 0);
  652.     fwrite("# ", sizeof(char), 2, dropf);
  653.     goto next_entry;
  654.     
  655.  err3:       
  656.     fclose(patternf);
  657.     unlink(temp_file);
  658.  err2:
  659.     fclose(compf);
  660.     rm_kill_file();
  661.  err1:
  662.     fclose(killf);
  663.     if (dropf != NULL) fclose(dropf);
  664.     
  665.     msg("cannot compile kill file");
  666.     return 0;
  667. }
  668.     
  669.  
  670. rm_kill_file()
  671. {    
  672.     unlink(relative(nn_directory, COMPILED_KILL));
  673. }
  674.  
  675.  
  676. free_kill_entries()
  677. {
  678.     register group_header *gh;
  679.  
  680.     Loop_Groups_Header(gh)
  681.     if (gh->kill_list) {
  682.         free_kill_list((kill_list_entry *)(gh->kill_list));
  683.         gh->kill_list = NULL;
  684.     }
  685.     
  686.     end_kill_list->next_kill = NULL;
  687.     free_kill_list(global_kill_list->next_kill);
  688.  
  689.     end_kill_list = global_kill_list = &dummy_kill;
  690.  
  691.     if (kill_patterns != NULL) free(kill_patterns);
  692.     if (kill_tab != NULL) free(kill_tab);
  693. }
  694.  
  695. static free_kill_list(kl)
  696. register kill_list_entry *kl;
  697. {
  698.     register kill_list_entry *nxt;
  699.     while (kl) {
  700.     nxt = kl->next_kill;
  701.     if (kl->kill_regexp != NULL) free(kl->kill_regexp);
  702.     if ((kl->kill_flag & COMP_KILL_ENTRY) == 0) {
  703.         if (kl->kill_pattern != NULL) free(kl->kill_pattern);
  704.         free(kl);
  705.     }
  706.     kl = nxt;
  707.     }
  708. }
  709.  
  710. dump_kill_list()
  711. {
  712.     register kill_list_entry *kl;
  713.  
  714.     pg_init(0, 1);
  715.     
  716.     pg_next();
  717.     so_printf("\1GLOBAL kill list entries:\1");
  718.     
  719.     kl = end_kill_list->next_kill = NULL;
  720.  
  721.     kl = global_kill_list;
  722.     while (kl = kl->next_kill) 
  723.     if (print_kill(kl) < 0) goto out;
  724.  
  725.     if (pg_next() < 0) goto out;
  726.     if (pg_next() < 0) goto out;
  727.  
  728.     kl = (kill_list_entry *)(current_group->kill_list);
  729.     if (kl == NULL) {
  730.     printf("No kill entries for %s", current_group->group_name);
  731.     goto out;
  732.     }
  733.     so_printf("\1GROUP %s kill list entries\1", current_group->group_name);
  734.     
  735.     while (kl) {
  736.     if (print_kill(kl) < 0) break;
  737.     kl = kl->next_kill;
  738.     }
  739.  
  740.  out:
  741.     
  742.     pg_end();
  743. }
  744.  
  745.  
  746.  
  747. print_kill(kl)
  748. register kill_list_entry *kl;
  749. {
  750.     if (pg_next() < 0) return -1;
  751.  
  752.     printf("\r%s ON %s '%.35s'%s\n",
  753.        kl->kill_flag & AUTO_KILL ? "KILL" : "SELECT",
  754.        kl->kill_flag & ON_SUBJECT ? "SUBJECT" : "NAME",
  755.        kl->kill_pattern,
  756.        kl->kill_flag & KILL_MUST_MATCH ? " (exact)" : 
  757.        kl->kill_flag & KILL_ON_REGEXP ? " (re)" : "");
  758.  
  759.     return 0;
  760. }
  761.  
  762.